﻿using MediatR;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;
using Traceability.Commont.DBContexts;
using Traceability.Commont.DomainEvenHanders;
using Traceability.Commont.Infrastructures.Interfaces;
using Traceability.Commont.Infrastructures.Repository;

namespace Traceability.Api.Commonts
{
    public static class ExtensionServiceCollection
    {
        public static void AddService(this IServiceCollection services, IConfiguration configuration)
        {

            services.AddDbContext<EFDBContext>(x => x.UseMySql(configuration.GetConnectionString("DB"), new MySqlServerVersion("8.4.2")));
            services.AddScoped(typeof(IBateRepository<>), typeof(BateRepository<>));
            services.AddAutoMapper(typeof(AutoMapperHelper));
            services.AddControllers();
            services.AddEndpointsApiExplorer();

            services.AddSwaggerGen(x =>
            {
                var path = AppDomain.CurrentDomain.BaseDirectory + "Traceability.Api.xml";
                x.IncludeXmlComments(path, true);
                x.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme()
                {
                    Description = "添加JWT授权Token：Bearer Token值",
                    Name = "Authorization",
                    In = Microsoft.OpenApi.Models.ParameterLocation.Header,
                    Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey,
                    BearerFormat = "JWT",
                    Scheme = "Bearer"
                });
                x.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement
                {
                    {
                        new OpenApiSecurityScheme
                        {
                            Reference = new OpenApiReference
                            {
                                Type = ReferenceType.SecurityScheme,
                                Id = "Bearer"
                            }
                        },
                        new string[]
                        {

                        }
                    }
                });
            });

            services.AddMediatR(typeof(Program), typeof(UserRolesCreateEvenHander));
            var jwtSettings = configuration.GetSection("JWT").Get<JWTfiles>();
            //添加认证
            //// 设置默认的身份验证为 JwtBearer
            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
            {
                // 配置 Token 验证参数
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    //过期时间容错值，解决服务器端时间不同步问题（秒）
                    //允许服务器时间偏移量30秒，即我们配置的过期时间加上这个允许偏移的时间值，才是真正过期的时间(过期时间 + 偏移值)你也可以设置为0，ClockSkew = TimeSpan.Zero
                    ClockSkew = TimeSpan.FromSeconds(30),
                    ValidateIssuer = true,// 验证发行者
                    ValidateAudience = true, // 验证受众
                    ValidateLifetime = true, // 验证令牌有效期
                    ValidateIssuerSigningKey = true,// 验证签名密钥
                    ValidIssuer = jwtSettings.Issuer,// 发行者
                    ValidAudience = jwtSettings.Audience,// 受众
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecurityKey))// 签名密钥
                };
            });
        }

        public static void AddDBContextService<T>(this IServiceCollection services, string connectionString, bool enableSqlLog = true) where T : DbContext
        {
            services.AddDbContext<T>(x =>
            {
                x.UseSqlServer(connectionString, action =>
                {
                    action.CommandTimeout(60);//超时时间
                                              //sql链接 错误重试策略 maxRetryCount：最大重试尝试次数。 maxRetryDelay：重试之间的最大延迟。
                    action.EnableRetryOnFailure(maxRetryCount: 5, maxRetryDelay: TimeSpan.FromSeconds(5), errorNumbersToAdd: null);
                })
                //在日志/错误消息 显示 敏感数据  如果不设置  sql语句参数 显示?  
                .EnableSensitiveDataLogging();
                if (enableSqlLog)
                {
                    //把sql语句 打印到控制台  可以过滤指定的日志级别
                    x.UseLoggerFactory(LoggerFactory.Create(configure =>
                    {
                        configure
                        .AddFilter((category, level) => category == DbLoggerCategory.Database.Command.Name && level == LogLevel.Information)
                        .AddConsole();
                    }));
                }
            });
        }
    }


}
